Introduction
The dynamics of flight pricing is a subject that interests and
affects travelers around the globe. According to ICAO’s statistics, the
total number of passengers carried on scheduled services rose to 4.5
billion in 2019, which is 3.6 per cent increase from the previous year,
while the number of departures reached 38.3 million in 2019, a 1.7 per
cent increase [3]. The upward trend for air travel is expected to
continue for each passing year which is why it is important for people
to understand what factors are behind these flight prices. Understanding
these factors could save them some money as they go to off to see their
families or go on a well deserved break. In this report, we will be
tackling the questions below:
Does departure time affect the price of the air ticket? Which
time has the cheapest and most expensive flight ticket?
Does the duration of the flight affect the price of the air
ticket?
Will the price of the flights be affected by the days
left?
Data
The data we used to investigate our questions is extracted from
Clean_Dataset.csv in the Flight Price Prediction datasets from Kaggle.
The dataset was sourced from https://www.kaggle.com/datasets/shubhambathwal/flight-price-prediction/data.
The dataset is prepared and complied by Shubham Bathwa. The data in the
dataset is collected from “Ease My Trip” website. Both data for economy
class flight tickets and business class flight tickets that traveled
between India’s top 6 metro cities are extracted from the website. The
data was collected over a period of 50 days.
The dataset contains 300,153 entries, each representing a flight
ticket from the “Ease My Trip” website. The dataset consists of 12
columns and each columns contains a flight information from the flight
ticket. The information represented in the columns are airline company,
flight code, source city, departure time, number of stops, arrival time,
destination city, ticket class, flight duration, days left to the day of
the flight, and price of the ticket. The dataset contains information on
6 unique airlines, 1,561 unique planes, 6 unique departure cities, 6
unique departure times, 6 unique arrival times, 6 unique destination
cities, and 2 unique types of classes.
Data Cleaning and Pre-processing
The first column of the dataset represents the row numbers for each
entry. As this information is not needed, the column containing the row
numbers is removed. Several columns in the dataset, such as airline,
flight, source city, departure time, stops, arrival time, destination
city, and class, are of character type. These columns are factorized for
easier data manipulation and analysis. The cleaned dataset now contains
11 columns, where 8 columns are the “factor” data type, and 3 are the
double data type.
# Loading the data
data <- read_csv("archive/Clean_Dataset.csv")
New names:
• `` -> `...1`
Rows: 300153 Columns: 12
── Column specification ───────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (8): airline, flight, source_city, departure_time, stops, arrival_time, destination_city, c...
dbl (4): ...1, duration, days_left, price
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Remove unnecessary column and factorized columns
df <- data %>% select(-1) %>%
mutate(across(c(airline, flight, source_city, departure_time, stops, arrival_time, destination_city, class), as.factor))
# Structure of dataset
str(df)
tibble [300,153 × 11] (S3: tbl_df/tbl/data.frame)
$ airline : Factor w/ 6 levels "Air_India","AirAsia",..: 5 5 2 6 6 6 6 6 3 3 ...
$ flight : Factor w/ 1561 levels "6E-102","6E-105",..: 1409 1388 1214 1560 1550 1542 1534 1544 1014 1015 ...
$ source_city : Factor w/ 6 levels "Bangalore","Chennai",..: 3 3 3 3 3 3 3 3 3 3 ...
$ departure_time : Factor w/ 6 levels "Afternoon","Early_Morning",..: 3 2 2 5 5 5 5 1 2 1 ...
$ stops : Factor w/ 3 levels "one","two_or_more",..: 3 3 3 3 3 3 3 3 3 3 ...
$ arrival_time : Factor w/ 6 levels "Afternoon","Early_Morning",..: 6 5 2 1 5 1 5 3 5 3 ...
$ destination_city: Factor w/ 6 levels "Bangalore","Chennai",..: 6 6 6 6 6 6 6 6 6 6 ...
$ class : Factor w/ 2 levels "Business","Economy": 2 2 2 2 2 2 2 2 2 2 ...
$ duration : num [1:300153] 2.17 2.33 2.17 2.25 2.33 2.33 2.08 2.17 2.17 2.25 ...
$ days_left : num [1:300153] 1 1 1 1 1 1 1 1 1 1 ...
$ price : num [1:300153] 5953 5953 5956 5955 5955 ...
# Print the dataset
df
Exploratory Data Analysis
# Summary of the dataset
summary(df)
airline flight source_city departure_time stops
Air_India: 80892 UK-706 : 3235 Bangalore:52061 Afternoon :47794 one :250863
AirAsia : 16098 UK-772 : 2741 Chennai :38700 Early_Morning:66790 two_or_more: 13286
GO_FIRST : 23173 UK-720 : 2650 Delhi :61343 Evening :65102 zero : 36004
Indigo : 43120 UK-836 : 2542 Hyderabad:40806 Late_Night : 1306
SpiceJet : 9011 UK-822 : 2468 Kolkata :46347 Morning :71146
Vistara :127859 UK-828 : 2440 Mumbai :60896 Night :48015
(Other):284077
arrival_time destination_city class duration days_left
Afternoon :38139 Bangalore:51068 Business: 93487 Min. : 0.83 Min. : 1
Early_Morning:15417 Chennai :40368 Economy :206666 1st Qu.: 6.83 1st Qu.:15
Evening :78323 Delhi :57360 Median :11.25 Median :26
Late_Night :14001 Hyderabad:42726 Mean :12.22 Mean :26
Morning :62735 Kolkata :49534 3rd Qu.:16.17 3rd Qu.:38
Night :91538 Mumbai :59097 Max. :49.83 Max. :49
price
Min. : 1105
1st Qu.: 4783
Median : 7425
Mean : 20890
3rd Qu.: 42521
Max. :123071
Visualizations & Interpretation
Question 1:
The boxplot shows that the medium of each departure time is
relatively similar, ranging between 6,500 and 8,200 Rupees. Late-night
departure time has a slightly lower medium than other departure times,
which is 4499 Rupee. However, it is difficult to determine which
departure time has the highest median based solely on the boxplot.
Furthermore, the boxplot also illustrates that late-night departure time
has the smallest interquartile range in price. In contrast, night
departure time has the largest interquartile range in price, indicating
greater price variability in flight tickets.
# Boxplot for flight prices by departure time
ggplot(df, aes(x = departure_time, y = price)) +
geom_boxplot() +
labs(title = "Flight Prices by Departure Time", x = "Departure Time", y = "Price") +
theme_minimal()

After further analysis by calculating the mean price of the flight
tickets, the late night departure time still has the cheapest flight
tickets compared to other departure times, which is 9295.299 Rupee. On
the other hand, night departure time has the most expensive flight
tickets compared to the departure times, standing at the mean of
23062.147 Rupee.
# Calculate the mean price by departure time
df_departure <- df %>%
group_by(departure_time) %>%
summarize(mean_price = mean(price))
# Display the mean flight ticket price in a table
kable(df_departure, caption = "Mean Price by Departure Time")
Mean Price by Departure Time
| Afternoon |
18179.203 |
| Early_Morning |
20370.677 |
| Evening |
21232.362 |
| Late_Night |
9295.299 |
| Morning |
21630.760 |
| Night |
23062.147 |
The histogram for night departure time prices demonstrates that the
data is right-skewed, with more records of flight ticket prices on the
lower end of the price range. However, the long tail of the histogram
does extend to higher prices. The histogram also has a smaller peak,
around 30,000 to 70,000 Rupees. This indicates that flight tickets with
night departure times are typically in the price range of the two
peaks.
# Get the entries for flights with Night departure times
df_night <- df %>% filter(departure_time == "Night")
# Plot histogram to investigate the distribution of the Night departure times flight price
ggplot(df_night, aes(x = price)) +
geom_histogram(bins = 30, fill = "lightblue", color = "black") +
labs(title = "Histogram of Night Flight Prices", x = "Price", y = "Frequency") +
theme_minimal()

The histogram for late-night flight ticket prices illustrates that
the data are heavily concentrated on the lower end. There are only a few
isolated outliers where flight prices exceed 20,000 Rupees. The
histogram also indicates that the frequency of late-night flight tickets
was drastically lower than the night departure times of flight
tickets.
# Get the entries for flights with Late Night departure times
df_late <- df %>% filter(departure_time == "Late_Night")
# Plot histogram to investigate the distribution of the Late Night departure times flight price
ggplot(df_late, aes(x = price)) +
geom_histogram(bins =30, fill = "lightblue", color = "black") +
labs(title = "Histogram of Late Night Flight Prices", x = "Price", y = "Frequency") +
theme_minimal()

Question 2:
The scatterplot reveals that there are two different clusters present
in the graph. Many of the points are concentrated on the lower left of
the graph, which indicates that many of the flight tickets are lower in
price and the flights have shorter duration. The positively sloped
trendline also demonstrates that the duration of the flights and the
price of flight tickets are positively correlated, where the longer the
flight duration, the higher the price of the flight tickets.
# Plot scatter and density plot to investigate the relationship between duration and the prices of the flight
ggplot(df, aes(x=duration, y=price)) +
geom_pointdensity(size = 0.5, alpha=0.05) +
scale_color_viridis_c() +
geom_smooth(method = "lm", formula = y ~ x, color = "red") +
labs(title = "Duration vs Price")

To further examine the relationship between the two clusters in the
scatterplot, we coloured the points based on the class of the flight
tickets. After applying the colour differentiation, the scatterplot
shows that the two clusters belong to the two ticket classes. Pink
cluster for business class flight tickets and blue cluster for economy
flight tickets. Business flight tickets are generally more expensive
than economy flight tickets. Thus, the cluster belonging to business
flight tickets is slightly higher in the graph than economy flight
tickets. The different ticket classes also explain the extensive range
of prices for the same flight duration.
# Scatterplot to show the class of the flight tickets
ggplot(df, aes(x = duration, y = price, color = class)) +
geom_point(size = 0.2, alpha = 0.3) +
geom_smooth(method = "lm", formula = y ~ x, color = "red") +
labs(title = "Duration vs Price", x = "Duration", y = "Price", color = "Class") +
theme_minimal()

The scatter-density plot for business-class flight tickets reveals
two main clusters of points. These clusters are centered around 25,000
and 60,000 Rupees. Both clusters fall within the duration range of 0 to
20 hours. The trend line in the graph highlights a positive relationship
between flight duration and ticket price, where longer flights generally
have higher prices for business-class tickets.
# Get the entries for business-class flight tickets
df_business <- df %>% filter(class == "Business")
# Plot hexagonal heatmap to investigate the relationship between duration and the prices of Business class flights
ggplot(df_business, aes(x = duration, y = price)) +
geom_pointdensity(size = 0.5, alpha = 0.5) +
scale_color_viridis_c() +
geom_smooth(method = "lm", formula = y ~ x, color = "red") +
labs(title = "Business Class's Duration vs Price", x = "Duration", y = "Price") +
theme_minimal()

Similar to the scatter-density plot for business-class flight
tickets, the graph has two main clusters for economy-class flight
tickets. One cluster is located around the price level of 2500 Rupees,
and the second cluster is around 50,000 Rupees. Most flights have
durations shorter than 20 hours, as indicated by the higher density of
points within this range. The trend line, similar to the previous graph,
has a positive relationship between flight duration and ticket
price.
# Get the entries for economy-class flight tickets
df_economy <- df %>% filter(class == "Economy")
# Plot hexagonal heatmap to investigate the relationship between duration and the prices of Economy class flights
ggplot(df_economy, aes(x = duration, y = price)) +
geom_pointdensity(size = 0.5, alpha = 0.5) +
scale_color_viridis_c() +
geom_smooth(method = "lm", formula = y ~ x, color = "red") +
labs(title = "Economy Class's Duration vs Price", x = "Duration", y = "Price") +
theme_minimal()

Question 3:
Below, we created a scatter plot to see if there is a correlation
between the days left from departure date and the price of the flight
ticket. Further more, we also categorized the plot by the source and
destination cities since we did not have individual flight numbers to
track.
library(ggplot2)
# Adding a new column "source_dest" which is a combination of
# source and destination city
combined_cities <- df %>% unite(source_dest, source_city, destination_city, sep = "_", remove = FALSE)
# Define the plotting function
plot_for_category <- function(cat, data) {
subset_data <- subset(data, source_dest == cat)
ggplot(subset_data, aes(x = days_left, y = price)) +
geom_point(color = "blue") +
geom_smooth(method = "lm", color = "red") +
labs(
title = paste("Plot for Category:", cat),
x = "Days before Departure",
y = "Price (Rupees)"
) +
theme_minimal()
}
# Get unique categories
unique_categories <- unique(combined_cities$source_dest)
# Generate and store plots for each category
plots <- lapply(unique_categories, function(cat) plot_for_category(cat, combined_cities))
# Display all plots
for (plot in plots) {
plot + ylim(0, 100000)
print(plot)
}
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'






























Machine Learning Models
First, we will be splitting the dataset into the training and testing
set to build our machine learning models. The training set will have 70
percent of the dataset and the testing set will have 30 percent of the
dataset. We also chose to create a sample training data of 10000 rows,
as it was taking our computers too long to compute the models using the
larger dataset.
set.seed(123)
smp_size <- floor(0.7 * nrow(df))
row_index <- sample(1: nrow(df), size = smp_size)
train_smp <- df[row_index, ]
test_smp <- df[-row_index, ]
sample_data <- train_smp[sample(nrow(train_smp), 10000), ]
Tree-Based Models
The first model we are using to predict the flight prices is the
tree-based model. In the model, we used categorical variable such as
departure time of the flight and continuous variables such as duration
of the flights and days left till the day of the flight. However, this
model did not do well in predicting the prices as the mean absolute
error is high and correlation is weak.
# Tree-Based Models
ar <- rpart(price ~ departure_time + duration + days_left,
train_smp)
preds <- predict(ar, test_smp)
# Calculate Mean Absolute Error (MAE)
mae <- mean(abs(preds - test_smp$price))
mae
[1] 18879.4
# Calculate correlation coefficient
cr <- cor(preds,test_smp$price)
cr
[1] 0.2592221
# Get the optimal cp value
optimal_cp <- ar$cptable[which.min(ar$cptable[,"xerror"]), "CP"]
# Prune the tree
pruned_tree <- prune(ar, cp = optimal_cp)
# Visualize the tree
rpart.plot(pruned_tree, box.palette = "Blues", main = "Simplified Decision Tree")

To make the model more accurate, we trained the tree-based model with
more independent variables. After retraining the model, the model now
produce predictions with extremely strong correlation and lower mean
absolute error compare to the last model.
# Train model with more variables
ar2 <- rpart(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city,
train_smp)
preds <- predict(ar2, test_smp)
# Calculate Mean Absolute Error (MAE)
mae <- mean(abs(preds - test_smp$price))
mae
[1] 4315.176
# Calculate correlation coefficient
cr <- cor(preds,test_smp$price)
cr
[1] 0.9569965
The plot shows that the flight class is the main predictor of the
flight ticket’s price. The duration of the flight further influences the
price of the business class flight.
# Get the optimal cp value
optimal_cp2 <- ar2$cptable[which.min(ar2$cptable[,"xerror"]), "CP"]
# Prune the tree
pruned_tree2 <- prune(ar2, cp = optimal_cp2)
# Visualize the tree
rpart.plot(pruned_tree2, box.palette = "Blues", main = "Simplified Decision Tree")

Linear Models
The next model we will be using to predict flight prices will be a
linear model.
# Remove Flight column from data frame
sample_data <- subset(sample_data, select = -c(flight))
#Get formula for LM
dependent_vars <- setdiff(names(sample_data), "price")
formula <- as.formula(paste("price ~", paste(dependent_vars, collapse = " + ")))
# Build the linear model
linear_model <- lm(formula, data = sample_data)
# Get predictions and MAE
lm_preds <- predict(linear_model, test_smp)
lm_mae <- mean(abs(lm_preds - test_smp$price))
lm_mae
[1] 4560.298
# Calculate correlation coefficient
lm_cr <- cor(lm_preds,test_smp$price)
lm_cr
[1] 0.9543588
Support Vector Machine
Support vector machine is one of the model we are using to predict
the price of the plane tickets. Independent variables such as departure
time of the flight, duration of the flight, days left to the flight,
number of stops, source city, airline, class, and destination_city are
used to predict the price of the flight tickets. Three different kernel
were used to find the suitable model. The radial SVM model performed the
best in predicting the flight prices as the model has the smallest mean
absolute error and highest correlation coefficient.
# linear svm model
s <- svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city,
sample_data,
kernel="linear")
s_preds <- predict(s, test_smp)
mae_s <- mean(abs(s_preds - test_smp$price))
mae_s
[1] 4183.375
cr_s <- cor(s_preds,test_smp$price)
cr_s
[1] 0.9514206
# radial svm model
r <- svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city,
sample_data,
kernel="radial")
r_preds <- predict(r, test_smp)
mae_r <- mean(abs(r_preds - test_smp$price))
mae_r
[1] 3139.727
cr_r <- cor(r_preds,test_smp$price)
cr_r
[1] 0.9731739
# poly svm model
poly <- svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city,
sample_data,
kernel="polynomial")
poly_preds <- predict(poly, test_smp)
mae_p <- mean(abs(poly_preds - test_smp$price))
mae_p
[1] 7739.832
cr_p <- cor(poly_preds,test_smp$price)
cr_p
[1] 0.91568
After tuning the radial SVM model, the model became more accurate as
the mean absolute error decreased and the correlation coefficient
increased. The best parameters for gamma and cost are 0.1 and 10,
respectively. A smaller random subset of 5000 entries was used to train
the fine-tuned model for efficiency.
# Take a smaller sample
sample_data2 <- train_smp[sample(nrow(train_smp), 5000), ]
# Find the best parameters
p <- tune.svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city,
data = sample_data2,
gamma=c(0.01, 0.1, 1),
cost=c(1, 5, 10) ,
kernel = "radial")
# Train the model with the best parameters
new_r <- svm(price ~ departure_time + duration + days_left + stops + source_city + airline + class + destination_city,
sample_data,
kernel="radial",
gamma=p$best.parameters$gamma,
cost=p$best.parameters$cost)
new_r_preds <- predict(new_r, test_smp)
# Calculate Mean Absolute Error (MAE)
new_mae_r <- mean(abs(new_r_preds - test_smp$price))
new_mae_r
[1] 2851.704
# Calculate correlation coefficient
new_cr_r <- cor(new_r_preds,test_smp$price)
new_cr_r
[1] 0.9783083
Conclusion
For this project we sought out to see if there are factors
influencing the flight prices. For our first question, we ask if there
was a correlation between the time of departure and the price of the
tickets. From a number of visualizations that we did, we can see that
there is definitely a correlation as late night tickets are usually the
cheapest with very little variability in price with a mean price of
9295.3 Rupees. For the remaining departure times, we can see that there
is not much difference in prices as the means of the rest of the
departure times center around 21000 Rupees.
For our second question, we tried to see if there was a correlation
between the duration of the flight and the ticket of the price. From
just looking a the trend line from the scatter plot, we can see a
positive correlation between the duration and the price of the ticket.
Upon further inspection of the scatter plot, after differentiating the
classes of the tickets, we can see the business class tickets get even
more expensive with duration than economy tickets.
For our last question, we wanted to see if there was a relation
between the days left from departure and the price of the ticket. We
used a scatter plot categorized by source and destination city and for
every plot we can see that there is a negative correlation between the
price and the days left from departure, the further the departure date
is the cheaper the tickets.
For our first tree model, we used only 3 indepandent variables
(departure time, duration, days_left) with our target variable, price,
to train our model. This did not lead to optimal results as we got a
mean absolute error of 18879.4 and a correlation coefficient of 0.2592.
So for our second tree model, we used all the variables in the data set
to train the model and we received better results with a mean absolute
error of 4315.176 and a correlation coefficient of 0.957.
For our linear model, we used all the variables in the data set to
train the model and a mean absolute error of 4560.298 and a correlation
coefficient of 0.954.
For our SVMs, first we trained 1 linear SVM, 1 radial SVM and 1
polynomial SVM using all the variables from the dataset. The table below
shows the mean absolute value and the correlation coefficient for each
of these models.
Mean absolute value Correlation coefficient
Linear SVM 4183.375 0.9514206
Radial SVM 3139.727 0.9731739
Polynomial SVM 7739.832 0.91568
We decided to tune the Radial SVM to make it more accurate by using
the best gamma and cost values. After tuning the models, the MAE
decreased to 2851.704 and the correlation coefficient rose to
0.9783.
After evaluating all our models, we can see that Radial SVM has the
best performance overall even before the tuning with a MAE of 3139.727
and a correlation coefficient of 0.973.
From this project, we can conclude that there are definitely factors
such as departure time, duration and the days left from departure
affecting the price of flight tickets.
Citations
[1] jan-glx, “Scatterplot with too many points,” Stack Overflow,
Oct. 10, 2011. https://stackoverflow.com/questions/7714677/scatterplot-with-too-many-points/58523956#58523956
[2] “How to Prune a Tree in R?,” GeeksforGeeks, Jun. 13, 2024. https://www.geeksforgeeks.org/how-to-prune-a-tree-in-r/
[3] https://www.icao.int/annual-report-2019/Pages/the-world-of-air-transport-in-2019.aspx#:~:text=The%204.5%20billion%20scheduled%20passengers,some%2090%20million%20in%202040.&text=The%20world’s%20major%20manufacturers%20delivered,822%20new%20aircraft%20net%20orders.
LS0tCnRpdGxlOiAiRmxpZ2h0IFByaWNlIEFuYWx5c2lzIGFuZCBQcmVkaWN0aW9uIgphdXRob3I6ICJUaHVuZSBLeWFlIFNpbiBTdSAtIEIwMDg2ODgwNiwgWXVraSBMYXcgLSBCMDA4NjU4ODUiCmdyb3VwOiAiSGFuZ3J5IGFuZCBBbmdyeSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShrbml0cikKbGlicmFyeShnZ3BvaW50ZGVuc2l0eSkKbGlicmFyeShETXdSMikKbGlicmFyeShycGFydC5wbG90KQpsaWJyYXJ5KHJwYXJ0KQpsaWJyYXJ5KGUxMDcxKQpgYGAKCiMjIEludHJvZHVjdGlvbgoKVGhlIGR5bmFtaWNzIG9mIGZsaWdodCBwcmljaW5nIGlzIGEgc3ViamVjdCB0aGF0IGludGVyZXN0cyBhbmQgYWZmZWN0cyB0cmF2ZWxlcnMgYXJvdW5kIHRoZSBnbG9iZS4gQWNjb3JkaW5nIHRvIElDQU8ncyBzdGF0aXN0aWNzLCB0aGUgdG90YWwgbnVtYmVyIG9mIHBhc3NlbmdlcnMgY2FycmllZCBvbiBzY2hlZHVsZWQgc2VydmljZXMgcm9zZSB0byA0LjUgYmlsbGlvbiBpbiAyMDE5LCB3aGljaCBpcyAzLjYgcGVyIGNlbnQgaW5jcmVhc2UgZnJvbSB0aGUgcHJldmlvdXMgeWVhciwgd2hpbGUgdGhlIG51bWJlciBvZiBkZXBhcnR1cmVzIHJlYWNoZWQgMzguMyBtaWxsaW9uIGluIDIwMTksIGEgMS43IHBlciBjZW50IGluY3JlYXNlIFszXS4gVGhlIHVwd2FyZCB0cmVuZCBmb3IgYWlyIHRyYXZlbCBpcyBleHBlY3RlZCB0byBjb250aW51ZSBmb3IgZWFjaCBwYXNzaW5nIHllYXIgd2hpY2ggaXMgd2h5IGl0IGlzIGltcG9ydGFudCBmb3IgcGVvcGxlIHRvIHVuZGVyc3RhbmQgd2hhdCBmYWN0b3JzIGFyZSBiZWhpbmQgdGhlc2UgZmxpZ2h0IHByaWNlcy4gVW5kZXJzdGFuZGluZyB0aGVzZSBmYWN0b3JzIGNvdWxkIHNhdmUgdGhlbSBzb21lIG1vbmV5IGFzIHRoZXkgZ28gdG8gb2ZmIHRvIHNlZSB0aGVpciBmYW1pbGllcyBvciBnbyBvbiBhIHdlbGwgZGVzZXJ2ZWQgYnJlYWsuIEluIHRoaXMgcmVwb3J0LCB3ZSB3aWxsIGJlIHRhY2tsaW5nIHRoZSBxdWVzdGlvbnMgYmVsb3c6CgoxLiAgRG9lcyBkZXBhcnR1cmUgdGltZSBhZmZlY3QgdGhlIHByaWNlIG9mIHRoZSBhaXIgdGlja2V0PyBXaGljaCB0aW1lIGhhcyB0aGUgY2hlYXBlc3QgYW5kIG1vc3QgZXhwZW5zaXZlIGZsaWdodCB0aWNrZXQ/CgoyLiAgRG9lcyB0aGUgZHVyYXRpb24gb2YgdGhlIGZsaWdodCBhZmZlY3QgdGhlIHByaWNlIG9mIHRoZSBhaXIgdGlja2V0PwoKMy4gIFdpbGwgdGhlIHByaWNlIG9mIHRoZSBmbGlnaHRzIGJlIGFmZmVjdGVkIGJ5IHRoZSBkYXlzIGxlZnQ/CgojIyBEYXRhCgpUaGUgZGF0YSB3ZSB1c2VkIHRvIGludmVzdGlnYXRlIG91ciBxdWVzdGlvbnMgaXMgZXh0cmFjdGVkIGZyb20gQ2xlYW5fRGF0YXNldC5jc3YgaW4gdGhlIEZsaWdodCBQcmljZSBQcmVkaWN0aW9uIGRhdGFzZXRzIGZyb20gS2FnZ2xlLiBUaGUgZGF0YXNldCB3YXMgc291cmNlZCBmcm9tIDxodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL3NodWJoYW1iYXRod2FsL2ZsaWdodC1wcmljZS1wcmVkaWN0aW9uL2RhdGE+LiBUaGUgZGF0YXNldCBpcyBwcmVwYXJlZCBhbmQgY29tcGxpZWQgYnkgU2h1YmhhbSBCYXRod2EuIFRoZSBkYXRhIGluIHRoZSBkYXRhc2V0IGlzIGNvbGxlY3RlZCBmcm9tIOKAnEVhc2UgTXkgVHJpcOKAnSB3ZWJzaXRlLiBCb3RoIGRhdGEgZm9yIGVjb25vbXkgY2xhc3MgZmxpZ2h0IHRpY2tldHMgYW5kIGJ1c2luZXNzIGNsYXNzIGZsaWdodCB0aWNrZXRzIHRoYXQgdHJhdmVsZWQgYmV0d2VlbiBJbmRpYSdzIHRvcCA2IG1ldHJvIGNpdGllcyBhcmUgZXh0cmFjdGVkIGZyb20gdGhlIHdlYnNpdGUuIFRoZSBkYXRhIHdhcyBjb2xsZWN0ZWQgb3ZlciBhIHBlcmlvZCBvZiA1MCBkYXlzLgoKVGhlIGRhdGFzZXQgY29udGFpbnMgMzAwLDE1MyBlbnRyaWVzLCBlYWNoIHJlcHJlc2VudGluZyBhIGZsaWdodCB0aWNrZXQgZnJvbSB0aGUg4oCcRWFzZSBNeSBUcmlw4oCdIHdlYnNpdGUuIFRoZSBkYXRhc2V0IGNvbnNpc3RzIG9mIDEyIGNvbHVtbnMgYW5kIGVhY2ggY29sdW1ucyBjb250YWlucyBhIGZsaWdodCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBmbGlnaHQgdGlja2V0LiBUaGUgaW5mb3JtYXRpb24gcmVwcmVzZW50ZWQgaW4gdGhlIGNvbHVtbnMgYXJlIGFpcmxpbmUgY29tcGFueSwgZmxpZ2h0IGNvZGUsIHNvdXJjZSBjaXR5LCBkZXBhcnR1cmUgdGltZSwgbnVtYmVyIG9mIHN0b3BzLCBhcnJpdmFsIHRpbWUsIGRlc3RpbmF0aW9uIGNpdHksIHRpY2tldCBjbGFzcywgZmxpZ2h0IGR1cmF0aW9uLCBkYXlzIGxlZnQgdG8gdGhlIGRheSBvZiB0aGUgZmxpZ2h0LCBhbmQgcHJpY2Ugb2YgdGhlIHRpY2tldC4gVGhlIGRhdGFzZXQgY29udGFpbnMgaW5mb3JtYXRpb24gb24gNiB1bmlxdWUgYWlybGluZXMsIDEsNTYxIHVuaXF1ZSBwbGFuZXMsIDYgdW5pcXVlIGRlcGFydHVyZSBjaXRpZXMsIDYgdW5pcXVlIGRlcGFydHVyZSB0aW1lcywgNiB1bmlxdWUgYXJyaXZhbCB0aW1lcywgNiB1bmlxdWUgZGVzdGluYXRpb24gY2l0aWVzLCBhbmQgMiB1bmlxdWUgdHlwZXMgb2YgY2xhc3Nlcy4KCiMjIERhdGEgQ2xlYW5pbmcgYW5kIFByZS1wcm9jZXNzaW5nCgpUaGUgZmlyc3QgY29sdW1uIG9mIHRoZSBkYXRhc2V0IHJlcHJlc2VudHMgdGhlIHJvdyBudW1iZXJzIGZvciBlYWNoIGVudHJ5LiBBcyB0aGlzIGluZm9ybWF0aW9uIGlzIG5vdCBuZWVkZWQsIHRoZSBjb2x1bW4gY29udGFpbmluZyB0aGUgcm93IG51bWJlcnMgaXMgcmVtb3ZlZC4gU2V2ZXJhbCBjb2x1bW5zIGluIHRoZSBkYXRhc2V0LCBzdWNoIGFzIGFpcmxpbmUsIGZsaWdodCwgc291cmNlIGNpdHksIGRlcGFydHVyZSB0aW1lLCBzdG9wcywgYXJyaXZhbCB0aW1lLCBkZXN0aW5hdGlvbiBjaXR5LCBhbmQgY2xhc3MsIGFyZSBvZiBjaGFyYWN0ZXIgdHlwZS4gVGhlc2UgY29sdW1ucyBhcmUgZmFjdG9yaXplZCBmb3IgZWFzaWVyIGRhdGEgbWFuaXB1bGF0aW9uIGFuZCBhbmFseXNpcy4gVGhlIGNsZWFuZWQgZGF0YXNldCBub3cgY29udGFpbnMgMTEgY29sdW1ucywgd2hlcmUgOCBjb2x1bW5zIGFyZSB0aGUgImZhY3RvciIgZGF0YSB0eXBlLCBhbmQgMyBhcmUgdGhlIGRvdWJsZSBkYXRhIHR5cGUuCgpgYGB7cn0KIyBMb2FkaW5nIHRoZSBkYXRhCmRhdGEgPC0gcmVhZF9jc3YoImFyY2hpdmUvQ2xlYW5fRGF0YXNldC5jc3YiKQoKIyBSZW1vdmUgdW5uZWNlc3NhcnkgY29sdW1uIGFuZCBmYWN0b3JpemVkIGNvbHVtbnMKZGYgPC0gZGF0YSAlPiUgc2VsZWN0KC0xKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoYWlybGluZSwgZmxpZ2h0LCBzb3VyY2VfY2l0eSwgZGVwYXJ0dXJlX3RpbWUsIHN0b3BzLCBhcnJpdmFsX3RpbWUsIGRlc3RpbmF0aW9uX2NpdHksIGNsYXNzKSwgYXMuZmFjdG9yKSkKCiMgU3RydWN0dXJlIG9mIGRhdGFzZXQKc3RyKGRmKQoKIyBQcmludCB0aGUgZGF0YXNldApkZgpgYGAKCiMjIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMKCmBgYHtyfQojIFN1bW1hcnkgb2YgdGhlIGRhdGFzZXQKc3VtbWFyeShkZikKYGBgCgojIyBWaXN1YWxpemF0aW9ucyAmIEludGVycHJldGF0aW9uCgpRdWVzdGlvbiAxOgoKVGhlIGJveHBsb3Qgc2hvd3MgdGhhdCB0aGUgbWVkaXVtIG9mIGVhY2ggZGVwYXJ0dXJlIHRpbWUgaXMgcmVsYXRpdmVseSBzaW1pbGFyLCByYW5naW5nIGJldHdlZW4gNiw1MDAgYW5kIDgsMjAwIFJ1cGVlcy4gTGF0ZS1uaWdodCBkZXBhcnR1cmUgdGltZSBoYXMgYSBzbGlnaHRseSBsb3dlciBtZWRpdW0gdGhhbiBvdGhlciBkZXBhcnR1cmUgdGltZXMsIHdoaWNoIGlzIDQ0OTkgUnVwZWUuIEhvd2V2ZXIsIGl0IGlzIGRpZmZpY3VsdCB0byBkZXRlcm1pbmUgd2hpY2ggZGVwYXJ0dXJlIHRpbWUgaGFzIHRoZSBoaWdoZXN0IG1lZGlhbiBiYXNlZCBzb2xlbHkgb24gdGhlIGJveHBsb3QuIEZ1cnRoZXJtb3JlLCB0aGUgYm94cGxvdCBhbHNvIGlsbHVzdHJhdGVzIHRoYXQgbGF0ZS1uaWdodCBkZXBhcnR1cmUgdGltZSBoYXMgdGhlIHNtYWxsZXN0IGludGVycXVhcnRpbGUgcmFuZ2UgaW4gcHJpY2UuIEluIGNvbnRyYXN0LCBuaWdodCBkZXBhcnR1cmUgdGltZSBoYXMgdGhlIGxhcmdlc3QgaW50ZXJxdWFydGlsZSByYW5nZSBpbiBwcmljZSwgaW5kaWNhdGluZyBncmVhdGVyIHByaWNlIHZhcmlhYmlsaXR5IGluIGZsaWdodCB0aWNrZXRzLgoKYGBge3J9CiMgQm94cGxvdCBmb3IgZmxpZ2h0IHByaWNlcyBieSBkZXBhcnR1cmUgdGltZQpnZ3Bsb3QoZGYsIGFlcyh4ID0gZGVwYXJ0dXJlX3RpbWUsIHkgPSBwcmljZSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICJGbGlnaHQgUHJpY2VzIGJ5IERlcGFydHVyZSBUaW1lIiwgeCA9ICJEZXBhcnR1cmUgVGltZSIsIHkgPSAiUHJpY2UiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKQWZ0ZXIgZnVydGhlciBhbmFseXNpcyBieSBjYWxjdWxhdGluZyB0aGUgbWVhbiBwcmljZSBvZiB0aGUgZmxpZ2h0IHRpY2tldHMsIHRoZSBsYXRlIG5pZ2h0IGRlcGFydHVyZSB0aW1lIHN0aWxsIGhhcyB0aGUgY2hlYXBlc3QgZmxpZ2h0IHRpY2tldHMgY29tcGFyZWQgdG8gb3RoZXIgZGVwYXJ0dXJlIHRpbWVzLCB3aGljaCBpcyA5Mjk1LjI5OSBSdXBlZS4gT24gdGhlIG90aGVyIGhhbmQsIG5pZ2h0IGRlcGFydHVyZSB0aW1lIGhhcyB0aGUgbW9zdCBleHBlbnNpdmUgZmxpZ2h0IHRpY2tldHMgY29tcGFyZWQgdG8gdGhlIGRlcGFydHVyZSB0aW1lcywgc3RhbmRpbmcgYXQgdGhlIG1lYW4gb2YgMjMwNjIuMTQ3IFJ1cGVlLgoKYGBge3J9CiMgQ2FsY3VsYXRlIHRoZSBtZWFuIHByaWNlIGJ5IGRlcGFydHVyZSB0aW1lCmRmX2RlcGFydHVyZSA8LSBkZiAlPiUKICBncm91cF9ieShkZXBhcnR1cmVfdGltZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fcHJpY2UgPSBtZWFuKHByaWNlKSkKCiMgRGlzcGxheSB0aGUgbWVhbiBmbGlnaHQgdGlja2V0IHByaWNlIGluIGEgdGFibGUKa2FibGUoZGZfZGVwYXJ0dXJlLCBjYXB0aW9uID0gIk1lYW4gUHJpY2UgYnkgRGVwYXJ0dXJlIFRpbWUiKQpgYGAKClRoZSBoaXN0b2dyYW0gZm9yIG5pZ2h0IGRlcGFydHVyZSB0aW1lIHByaWNlcyBkZW1vbnN0cmF0ZXMgdGhhdCB0aGUgZGF0YSBpcyByaWdodC1za2V3ZWQsIHdpdGggbW9yZSByZWNvcmRzIG9mIGZsaWdodCB0aWNrZXQgcHJpY2VzIG9uIHRoZSBsb3dlciBlbmQgb2YgdGhlIHByaWNlIHJhbmdlLiBIb3dldmVyLCB0aGUgbG9uZyB0YWlsIG9mIHRoZSBoaXN0b2dyYW0gZG9lcyBleHRlbmQgdG8gaGlnaGVyIHByaWNlcy4gVGhlIGhpc3RvZ3JhbSBhbHNvIGhhcyBhIHNtYWxsZXIgcGVhaywgYXJvdW5kIDMwLDAwMCB0byA3MCwwMDAgUnVwZWVzLiBUaGlzIGluZGljYXRlcyB0aGF0IGZsaWdodCB0aWNrZXRzIHdpdGggbmlnaHQgZGVwYXJ0dXJlIHRpbWVzIGFyZSB0eXBpY2FsbHkgaW4gdGhlIHByaWNlIHJhbmdlIG9mIHRoZSB0d28gcGVha3MuCgpgYGB7cn0KIyBHZXQgdGhlIGVudHJpZXMgZm9yIGZsaWdodHMgd2l0aCBOaWdodCBkZXBhcnR1cmUgdGltZXMKZGZfbmlnaHQgPC0gZGYgJT4lIGZpbHRlcihkZXBhcnR1cmVfdGltZSA9PSAiTmlnaHQiKQoKIyBQbG90IGhpc3RvZ3JhbSB0byBpbnZlc3RpZ2F0ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBOaWdodCBkZXBhcnR1cmUgdGltZXMgZmxpZ2h0IHByaWNlCmdncGxvdChkZl9uaWdodCwgYWVzKHggPSBwcmljZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzAsIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgTmlnaHQgRmxpZ2h0IFByaWNlcyIsIHggPSAiUHJpY2UiLCB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgpUaGUgaGlzdG9ncmFtIGZvciBsYXRlLW5pZ2h0IGZsaWdodCB0aWNrZXQgcHJpY2VzIGlsbHVzdHJhdGVzIHRoYXQgdGhlIGRhdGEgYXJlIGhlYXZpbHkgY29uY2VudHJhdGVkIG9uIHRoZSBsb3dlciBlbmQuIFRoZXJlIGFyZSBvbmx5IGEgZmV3IGlzb2xhdGVkIG91dGxpZXJzIHdoZXJlIGZsaWdodCBwcmljZXMgZXhjZWVkIDIwLDAwMCBSdXBlZXMuIFRoZSBoaXN0b2dyYW0gYWxzbyBpbmRpY2F0ZXMgdGhhdCB0aGUgZnJlcXVlbmN5IG9mIGxhdGUtbmlnaHQgZmxpZ2h0IHRpY2tldHMgd2FzIGRyYXN0aWNhbGx5IGxvd2VyIHRoYW4gdGhlIG5pZ2h0IGRlcGFydHVyZSB0aW1lcyBvZiBmbGlnaHQgdGlja2V0cy4KCmBgYHtyfQojIEdldCB0aGUgZW50cmllcyBmb3IgZmxpZ2h0cyB3aXRoIExhdGUgTmlnaHQgZGVwYXJ0dXJlIHRpbWVzCmRmX2xhdGUgPC0gZGYgJT4lIGZpbHRlcihkZXBhcnR1cmVfdGltZSA9PSAiTGF0ZV9OaWdodCIpCgojIFBsb3QgaGlzdG9ncmFtIHRvIGludmVzdGlnYXRlIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIExhdGUgTmlnaHQgZGVwYXJ0dXJlIHRpbWVzIGZsaWdodCBwcmljZQpnZ3Bsb3QoZGZfbGF0ZSwgYWVzKHggPSBwcmljZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0zMCwgZmlsbCA9ICJsaWdodGJsdWUiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBMYXRlIE5pZ2h0IEZsaWdodCBQcmljZXMiLCB4ID0gIlByaWNlIiwgeSA9ICJGcmVxdWVuY3kiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKUXVlc3Rpb24gMjoKClRoZSBzY2F0dGVycGxvdCByZXZlYWxzIHRoYXQgdGhlcmUgYXJlIHR3byBkaWZmZXJlbnQgY2x1c3RlcnMgcHJlc2VudCBpbiB0aGUgZ3JhcGguIE1hbnkgb2YgdGhlIHBvaW50cyBhcmUgY29uY2VudHJhdGVkIG9uIHRoZSBsb3dlciBsZWZ0IG9mIHRoZSBncmFwaCwgd2hpY2ggaW5kaWNhdGVzIHRoYXQgbWFueSBvZiB0aGUgZmxpZ2h0IHRpY2tldHMgYXJlIGxvd2VyIGluIHByaWNlIGFuZCB0aGUgZmxpZ2h0cyBoYXZlIHNob3J0ZXIgZHVyYXRpb24uIFRoZSBwb3NpdGl2ZWx5IHNsb3BlZCB0cmVuZGxpbmUgYWxzbyBkZW1vbnN0cmF0ZXMgdGhhdCB0aGUgZHVyYXRpb24gb2YgdGhlIGZsaWdodHMgYW5kIHRoZSBwcmljZSBvZiBmbGlnaHQgdGlja2V0cyBhcmUgcG9zaXRpdmVseSBjb3JyZWxhdGVkLCB3aGVyZSB0aGUgbG9uZ2VyIHRoZSBmbGlnaHQgZHVyYXRpb24sIHRoZSBoaWdoZXIgdGhlIHByaWNlIG9mIHRoZSBmbGlnaHQgdGlja2V0cy4KCmBgYHtyfQojIFBsb3Qgc2NhdHRlciBhbmQgZGVuc2l0eSBwbG90IHRvIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBkdXJhdGlvbiBhbmQgdGhlIHByaWNlcyBvZiB0aGUgZmxpZ2h0IApnZ3Bsb3QoZGYsIGFlcyh4PWR1cmF0aW9uLCB5PXByaWNlKSkgKyAKICBnZW9tX3BvaW50ZGVuc2l0eShzaXplID0gMC41LCBhbHBoYT0wLjA1KSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkR1cmF0aW9uIHZzIFByaWNlIikKYGBgCgpUbyBmdXJ0aGVyIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0d28gY2x1c3RlcnMgaW4gdGhlIHNjYXR0ZXJwbG90LCB3ZSBjb2xvdXJlZCB0aGUgcG9pbnRzIGJhc2VkIG9uIHRoZSBjbGFzcyBvZiB0aGUgZmxpZ2h0IHRpY2tldHMuIEFmdGVyIGFwcGx5aW5nIHRoZSBjb2xvdXIgZGlmZmVyZW50aWF0aW9uLCB0aGUgc2NhdHRlcnBsb3Qgc2hvd3MgdGhhdCB0aGUgdHdvIGNsdXN0ZXJzIGJlbG9uZyB0byB0aGUgdHdvIHRpY2tldCBjbGFzc2VzLiBQaW5rIGNsdXN0ZXIgZm9yIGJ1c2luZXNzIGNsYXNzIGZsaWdodCB0aWNrZXRzIGFuZCBibHVlIGNsdXN0ZXIgZm9yIGVjb25vbXkgZmxpZ2h0IHRpY2tldHMuIEJ1c2luZXNzIGZsaWdodCB0aWNrZXRzIGFyZSBnZW5lcmFsbHkgbW9yZSBleHBlbnNpdmUgdGhhbiBlY29ub215IGZsaWdodCB0aWNrZXRzLiBUaHVzLCB0aGUgY2x1c3RlciBiZWxvbmdpbmcgdG8gYnVzaW5lc3MgZmxpZ2h0IHRpY2tldHMgaXMgc2xpZ2h0bHkgaGlnaGVyIGluIHRoZSBncmFwaCB0aGFuIGVjb25vbXkgZmxpZ2h0IHRpY2tldHMuIFRoZSBkaWZmZXJlbnQgdGlja2V0IGNsYXNzZXMgYWxzbyBleHBsYWluIHRoZSBleHRlbnNpdmUgcmFuZ2Ugb2YgcHJpY2VzIGZvciB0aGUgc2FtZSBmbGlnaHQgZHVyYXRpb24uCgpgYGB7cn0KIyBTY2F0dGVycGxvdCB0byBzaG93IHRoZSBjbGFzcyBvZiB0aGUgZmxpZ2h0IHRpY2tldHMKZ2dwbG90KGRmLCBhZXMoeCA9IGR1cmF0aW9uLCB5ID0gcHJpY2UsIGNvbG9yID0gY2xhc3MpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4yLCBhbHBoYSA9IDAuMykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgY29sb3IgPSAicmVkIikgKwogIGxhYnModGl0bGUgPSAiRHVyYXRpb24gdnMgUHJpY2UiLCB4ID0gIkR1cmF0aW9uIiwgeSA9ICJQcmljZSIsIGNvbG9yID0gIkNsYXNzIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKClRoZSBzY2F0dGVyLWRlbnNpdHkgcGxvdCBmb3IgYnVzaW5lc3MtY2xhc3MgZmxpZ2h0IHRpY2tldHMgcmV2ZWFscyB0d28gbWFpbiBjbHVzdGVycyBvZiBwb2ludHMuIFRoZXNlIGNsdXN0ZXJzIGFyZSBjZW50ZXJlZCBhcm91bmQgMjUsMDAwIGFuZCA2MCwwMDAgUnVwZWVzLiBCb3RoIGNsdXN0ZXJzIGZhbGwgd2l0aGluIHRoZSBkdXJhdGlvbiByYW5nZSBvZiAwIHRvIDIwIGhvdXJzLiBUaGUgdHJlbmQgbGluZSBpbiB0aGUgZ3JhcGggaGlnaGxpZ2h0cyBhIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGZsaWdodCBkdXJhdGlvbiBhbmQgdGlja2V0IHByaWNlLCB3aGVyZSBsb25nZXIgZmxpZ2h0cyBnZW5lcmFsbHkgaGF2ZSBoaWdoZXIgcHJpY2VzIGZvciBidXNpbmVzcy1jbGFzcyB0aWNrZXRzLgoKYGBge3J9CiMgR2V0IHRoZSBlbnRyaWVzIGZvciBidXNpbmVzcy1jbGFzcyBmbGlnaHQgdGlja2V0cwpkZl9idXNpbmVzcyA8LSBkZiAlPiUgZmlsdGVyKGNsYXNzID09ICJCdXNpbmVzcyIpCgojIFBsb3QgaGV4YWdvbmFsIGhlYXRtYXAgdG8gaW52ZXN0aWdhdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGR1cmF0aW9uIGFuZCB0aGUgcHJpY2VzIG9mIEJ1c2luZXNzIGNsYXNzIGZsaWdodHMKZ2dwbG90KGRmX2J1c2luZXNzLCBhZXMoeCA9IGR1cmF0aW9uLCB5ID0gcHJpY2UpKSArIAogIGdlb21fcG9pbnRkZW5zaXR5KHNpemUgPSAwLjUsIGFscGhhID0gMC41KSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkJ1c2luZXNzIENsYXNzJ3MgRHVyYXRpb24gdnMgUHJpY2UiLCB4ID0gIkR1cmF0aW9uIiwgeSA9ICJQcmljZSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgpTaW1pbGFyIHRvIHRoZSBzY2F0dGVyLWRlbnNpdHkgcGxvdCBmb3IgYnVzaW5lc3MtY2xhc3MgZmxpZ2h0IHRpY2tldHMsIHRoZSBncmFwaCBoYXMgdHdvIG1haW4gY2x1c3RlcnMgZm9yIGVjb25vbXktY2xhc3MgZmxpZ2h0IHRpY2tldHMuIE9uZSBjbHVzdGVyIGlzIGxvY2F0ZWQgYXJvdW5kIHRoZSBwcmljZSBsZXZlbCBvZiAyNTAwIFJ1cGVlcywgYW5kIHRoZSBzZWNvbmQgY2x1c3RlciBpcyBhcm91bmQgNTAsMDAwIFJ1cGVlcy4gTW9zdCBmbGlnaHRzIGhhdmUgZHVyYXRpb25zIHNob3J0ZXIgdGhhbiAyMCBob3VycywgYXMgaW5kaWNhdGVkIGJ5IHRoZSBoaWdoZXIgZGVuc2l0eSBvZiBwb2ludHMgd2l0aGluIHRoaXMgcmFuZ2UuIFRoZSB0cmVuZCBsaW5lLCBzaW1pbGFyIHRvIHRoZSBwcmV2aW91cyBncmFwaCwgaGFzIGEgcG9zaXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gZmxpZ2h0IGR1cmF0aW9uIGFuZCB0aWNrZXQgcHJpY2UuCgpgYGB7cn0KIyBHZXQgdGhlIGVudHJpZXMgZm9yIGVjb25vbXktY2xhc3MgZmxpZ2h0IHRpY2tldHMKZGZfZWNvbm9teSA8LSBkZiAlPiUgZmlsdGVyKGNsYXNzID09ICJFY29ub215IikKCiMgUGxvdCBoZXhhZ29uYWwgaGVhdG1hcCB0byBpbnZlc3RpZ2F0ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZHVyYXRpb24gYW5kIHRoZSBwcmljZXMgb2YgRWNvbm9teSBjbGFzcyBmbGlnaHRzCmdncGxvdChkZl9lY29ub215LCBhZXMoeCA9IGR1cmF0aW9uLCB5ID0gcHJpY2UpKSArIAogIGdlb21fcG9pbnRkZW5zaXR5KHNpemUgPSAwLjUsIGFscGhhID0gMC41KSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkVjb25vbXkgQ2xhc3MncyBEdXJhdGlvbiB2cyBQcmljZSIsIHggPSAiRHVyYXRpb24iLCB5ID0gIlByaWNlIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKClF1ZXN0aW9uIDM6CgpCZWxvdywgd2UgY3JlYXRlZCBhIHNjYXR0ZXIgcGxvdCB0byBzZWUgaWYgdGhlcmUgaXMgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBkYXlzIGxlZnQgZnJvbSBkZXBhcnR1cmUgZGF0ZSBhbmQgdGhlIHByaWNlIG9mIHRoZSBmbGlnaHQgdGlja2V0LiBGdXJ0aGVyIG1vcmUsIHdlIGFsc28gY2F0ZWdvcml6ZWQgdGhlIHBsb3QgYnkgdGhlIHNvdXJjZSBhbmQgZGVzdGluYXRpb24gY2l0aWVzIHNpbmNlIHdlIGRpZCBub3QgaGF2ZSBpbmRpdmlkdWFsIGZsaWdodCBudW1iZXJzIHRvIHRyYWNrLgoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKCiMgQWRkaW5nIGEgbmV3IGNvbHVtbiAic291cmNlX2Rlc3QiIHdoaWNoIGlzIGEgY29tYmluYXRpb24gb2YgCiMgc291cmNlIGFuZCBkZXN0aW5hdGlvbiBjaXR5CmNvbWJpbmVkX2NpdGllcyA8LSBkZiAlPiUgdW5pdGUoc291cmNlX2Rlc3QsIHNvdXJjZV9jaXR5LCBkZXN0aW5hdGlvbl9jaXR5LCBzZXAgPSAiXyIsIHJlbW92ZSA9IEZBTFNFKQoKIyBEZWZpbmUgdGhlIHBsb3R0aW5nIGZ1bmN0aW9uCnBsb3RfZm9yX2NhdGVnb3J5IDwtIGZ1bmN0aW9uKGNhdCwgZGF0YSkgewogIHN1YnNldF9kYXRhIDwtIHN1YnNldChkYXRhLCBzb3VyY2VfZGVzdCA9PSBjYXQpCiAgCiAgZ2dwbG90KHN1YnNldF9kYXRhLCBhZXMoeCA9IGRheXNfbGVmdCwgeSA9IHByaWNlKSkgKwogICAgZ2VvbV9wb2ludChjb2xvciA9ICJibHVlIikgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAicmVkIikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSBwYXN0ZSgiUGxvdCBmb3IgQ2F0ZWdvcnk6IiwgY2F0KSwKICAgICAgeCA9ICJEYXlzIGJlZm9yZSBEZXBhcnR1cmUiLAogICAgICB5ID0gIlByaWNlIChSdXBlZXMpIgogICAgKSArCiAgICB0aGVtZV9taW5pbWFsKCkKfQoKIyBHZXQgdW5pcXVlIGNhdGVnb3JpZXMKdW5pcXVlX2NhdGVnb3JpZXMgPC0gdW5pcXVlKGNvbWJpbmVkX2NpdGllcyRzb3VyY2VfZGVzdCkKCiMgR2VuZXJhdGUgYW5kIHN0b3JlIHBsb3RzIGZvciBlYWNoIGNhdGVnb3J5CnBsb3RzIDwtIGxhcHBseSh1bmlxdWVfY2F0ZWdvcmllcywgZnVuY3Rpb24oY2F0KSBwbG90X2Zvcl9jYXRlZ29yeShjYXQsIGNvbWJpbmVkX2NpdGllcykpCgojIERpc3BsYXkgYWxsIHBsb3RzIApmb3IgKHBsb3QgaW4gcGxvdHMpIHsKICBwbG90ICsgeWxpbSgwLCAxMDAwMDApCiAgcHJpbnQocGxvdCkKfQpgYGAKCiMjIE1hY2hpbmUgTGVhcm5pbmcgTW9kZWxzCgpGaXJzdCwgd2Ugd2lsbCBiZSBzcGxpdHRpbmcgdGhlIGRhdGFzZXQgaW50byB0aGUgdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc2V0IHRvIGJ1aWxkIG91ciBtYWNoaW5lIGxlYXJuaW5nIG1vZGVscy4gVGhlIHRyYWluaW5nIHNldCB3aWxsIGhhdmUgNzAgcGVyY2VudCBvZiB0aGUgZGF0YXNldCBhbmQgdGhlIHRlc3Rpbmcgc2V0IHdpbGwgaGF2ZSAzMCBwZXJjZW50IG9mIHRoZSBkYXRhc2V0LiBXZSBhbHNvIGNob3NlIHRvIGNyZWF0ZSBhIHNhbXBsZSB0cmFpbmluZyBkYXRhIG9mIDEwMDAwIHJvd3MsIGFzIGl0IHdhcyB0YWtpbmcgb3VyIGNvbXB1dGVycyB0b28gbG9uZyB0byBjb21wdXRlIHRoZSBtb2RlbHMgdXNpbmcgdGhlIGxhcmdlciBkYXRhc2V0LgoKYGBge3J9CnNldC5zZWVkKDEyMykKc21wX3NpemUgPC0gZmxvb3IoMC43ICogbnJvdyhkZikpCnJvd19pbmRleCA8LSBzYW1wbGUoMTogbnJvdyhkZiksIHNpemUgPSBzbXBfc2l6ZSkKdHJhaW5fc21wIDwtIGRmW3Jvd19pbmRleCwgXQp0ZXN0X3NtcCA8LSBkZlstcm93X2luZGV4LCBdCnNhbXBsZV9kYXRhIDwtIHRyYWluX3NtcFtzYW1wbGUobnJvdyh0cmFpbl9zbXApLCAxMDAwMCksIF0KYGBgCgojIyMgVHJlZS1CYXNlZCBNb2RlbHMKClRoZSBmaXJzdCBtb2RlbCB3ZSBhcmUgdXNpbmcgdG8gcHJlZGljdCB0aGUgZmxpZ2h0IHByaWNlcyBpcyB0aGUgdHJlZS1iYXNlZCBtb2RlbC4gSW4gdGhlIG1vZGVsLCB3ZSB1c2VkIGNhdGVnb3JpY2FsIHZhcmlhYmxlIHN1Y2ggYXMgZGVwYXJ0dXJlIHRpbWUgb2YgdGhlIGZsaWdodCBhbmQgY29udGludW91cyB2YXJpYWJsZXMgc3VjaCBhcyBkdXJhdGlvbiBvZiB0aGUgZmxpZ2h0cyBhbmQgZGF5cyBsZWZ0IHRpbGwgdGhlIGRheSBvZiB0aGUgZmxpZ2h0LiBIb3dldmVyLCB0aGlzIG1vZGVsIGRpZCBub3QgZG8gd2VsbCBpbiBwcmVkaWN0aW5nIHRoZSBwcmljZXMgYXMgdGhlIG1lYW4gYWJzb2x1dGUgZXJyb3IgaXMgaGlnaCBhbmQgY29ycmVsYXRpb24gaXMgd2Vhay4KCmBgYHtyfQojIFRyZWUtQmFzZWQgTW9kZWxzCmFyIDwtIHJwYXJ0KHByaWNlIH4gZGVwYXJ0dXJlX3RpbWUgKyBkdXJhdGlvbiArIGRheXNfbGVmdCwgCiAgICAgICAgICAgIHRyYWluX3NtcCkKcHJlZHMgPC0gcHJlZGljdChhciwgdGVzdF9zbXApCgojIENhbGN1bGF0ZSBNZWFuIEFic29sdXRlIEVycm9yIChNQUUpCm1hZSA8LSBtZWFuKGFicyhwcmVkcyAtIHRlc3Rfc21wJHByaWNlKSkKbWFlCgojIENhbGN1bGF0ZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudApjciA8LSBjb3IocHJlZHMsdGVzdF9zbXAkcHJpY2UpCmNyCgojIEdldCB0aGUgb3B0aW1hbCBjcCB2YWx1ZQpvcHRpbWFsX2NwIDwtIGFyJGNwdGFibGVbd2hpY2gubWluKGFyJGNwdGFibGVbLCJ4ZXJyb3IiXSksICJDUCJdCgojIFBydW5lIHRoZSB0cmVlCnBydW5lZF90cmVlIDwtIHBydW5lKGFyLCBjcCA9IG9wdGltYWxfY3ApCgojIFZpc3VhbGl6ZSB0aGUgdHJlZQpycGFydC5wbG90KHBydW5lZF90cmVlLCBib3gucGFsZXR0ZSA9ICJCbHVlcyIsIG1haW4gPSAiU2ltcGxpZmllZCBEZWNpc2lvbiBUcmVlIikKYGBgCgpUbyBtYWtlIHRoZSBtb2RlbCBtb3JlIGFjY3VyYXRlLCB3ZSB0cmFpbmVkIHRoZSB0cmVlLWJhc2VkIG1vZGVsIHdpdGggbW9yZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMuIEFmdGVyIHJldHJhaW5pbmcgdGhlIG1vZGVsLCB0aGUgbW9kZWwgbm93IHByb2R1Y2UgcHJlZGljdGlvbnMgd2l0aCBleHRyZW1lbHkgc3Ryb25nIGNvcnJlbGF0aW9uIGFuZCBsb3dlciBtZWFuIGFic29sdXRlIGVycm9yIGNvbXBhcmUgdG8gdGhlIGxhc3QgbW9kZWwuCgpgYGB7cn0KIyBUcmFpbiBtb2RlbCB3aXRoIG1vcmUgdmFyaWFibGVzCmFyMiA8LSBycGFydChwcmljZSB+IGRlcGFydHVyZV90aW1lICsgZHVyYXRpb24gKyBkYXlzX2xlZnQgKyBzdG9wcyArIHNvdXJjZV9jaXR5ICsgYWlybGluZSArIGNsYXNzICsgZGVzdGluYXRpb25fY2l0eSwKICAgICAgICAgICAgdHJhaW5fc21wKQpwcmVkcyA8LSBwcmVkaWN0KGFyMiwgdGVzdF9zbXApCgojIENhbGN1bGF0ZSBNZWFuIEFic29sdXRlIEVycm9yIChNQUUpCm1hZSA8LSBtZWFuKGFicyhwcmVkcyAtIHRlc3Rfc21wJHByaWNlKSkKbWFlCgojIENhbGN1bGF0ZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudApjciA8LSBjb3IocHJlZHMsdGVzdF9zbXAkcHJpY2UpCmNyCmBgYAoKVGhlIHBsb3Qgc2hvd3MgdGhhdCB0aGUgZmxpZ2h0IGNsYXNzIGlzIHRoZSBtYWluIHByZWRpY3RvciBvZiB0aGUgZmxpZ2h0IHRpY2tldCdzIHByaWNlLiBUaGUgZHVyYXRpb24gb2YgdGhlIGZsaWdodCBmdXJ0aGVyIGluZmx1ZW5jZXMgdGhlIHByaWNlIG9mIHRoZSBidXNpbmVzcyBjbGFzcyBmbGlnaHQuCgpgYGB7cn0KIyBHZXQgdGhlIG9wdGltYWwgY3AgdmFsdWUKb3B0aW1hbF9jcDIgPC0gYXIyJGNwdGFibGVbd2hpY2gubWluKGFyMiRjcHRhYmxlWywieGVycm9yIl0pLCAiQ1AiXQoKIyBQcnVuZSB0aGUgdHJlZQpwcnVuZWRfdHJlZTIgPC0gcHJ1bmUoYXIyLCBjcCA9IG9wdGltYWxfY3AyKQoKIyBWaXN1YWxpemUgdGhlIHRyZWUKcnBhcnQucGxvdChwcnVuZWRfdHJlZTIsIGJveC5wYWxldHRlID0gIkJsdWVzIiwgbWFpbiA9ICJTaW1wbGlmaWVkIERlY2lzaW9uIFRyZWUiKQpgYGAKCiMjIExpbmVhciBNb2RlbHMKClRoZSBuZXh0IG1vZGVsIHdlIHdpbGwgYmUgdXNpbmcgdG8gcHJlZGljdCBmbGlnaHQgcHJpY2VzIHdpbGwgYmUgYSBsaW5lYXIgbW9kZWwuCgpgYGB7cn0KIyBSZW1vdmUgRmxpZ2h0IGNvbHVtbiBmcm9tIGRhdGEgZnJhbWUKc2FtcGxlX2RhdGEgPC0gc3Vic2V0KHNhbXBsZV9kYXRhLCBzZWxlY3QgPSAtYyhmbGlnaHQpKQoKI0dldCBmb3JtdWxhIGZvciBMTQpkZXBlbmRlbnRfdmFycyA8LSBzZXRkaWZmKG5hbWVzKHNhbXBsZV9kYXRhKSwgInByaWNlIikKZm9ybXVsYSA8LSBhcy5mb3JtdWxhKHBhc3RlKCJwcmljZSB+IiwgcGFzdGUoZGVwZW5kZW50X3ZhcnMsIGNvbGxhcHNlID0gIiArICIpKSkKCiMgQnVpbGQgdGhlIGxpbmVhciBtb2RlbApsaW5lYXJfbW9kZWwgPC0gbG0oZm9ybXVsYSwgZGF0YSA9IHNhbXBsZV9kYXRhKQpgYGAKCmBgYHtyfQojIEdldCBwcmVkaWN0aW9ucyBhbmQgTUFFCmxtX3ByZWRzIDwtIHByZWRpY3QobGluZWFyX21vZGVsLCB0ZXN0X3NtcCkKbG1fbWFlIDwtIG1lYW4oYWJzKGxtX3ByZWRzIC0gdGVzdF9zbXAkcHJpY2UpKQpsbV9tYWUKCiMgQ2FsY3VsYXRlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50CmxtX2NyIDwtIGNvcihsbV9wcmVkcyx0ZXN0X3NtcCRwcmljZSkKbG1fY3IKYGBgCgojIyBTdXBwb3J0IFZlY3RvciBNYWNoaW5lCgpTdXBwb3J0IHZlY3RvciBtYWNoaW5lIGlzIG9uZSBvZiB0aGUgbW9kZWwgd2UgYXJlIHVzaW5nIHRvIHByZWRpY3QgdGhlIHByaWNlIG9mIHRoZSBwbGFuZSB0aWNrZXRzLiBJbmRlcGVuZGVudCB2YXJpYWJsZXMgc3VjaCBhcyBkZXBhcnR1cmUgdGltZSBvZiB0aGUgZmxpZ2h0LCBkdXJhdGlvbiBvZiB0aGUgZmxpZ2h0LCBkYXlzIGxlZnQgdG8gdGhlIGZsaWdodCwgbnVtYmVyIG9mIHN0b3BzLCBzb3VyY2UgY2l0eSwgYWlybGluZSwgY2xhc3MsIGFuZCBkZXN0aW5hdGlvbl9jaXR5IGFyZSB1c2VkIHRvIHByZWRpY3QgdGhlIHByaWNlIG9mIHRoZSBmbGlnaHQgdGlja2V0cy4gVGhyZWUgZGlmZmVyZW50IGtlcm5lbCB3ZXJlIHVzZWQgdG8gZmluZCB0aGUgc3VpdGFibGUgbW9kZWwuIFRoZSByYWRpYWwgU1ZNIG1vZGVsIHBlcmZvcm1lZCB0aGUgYmVzdCBpbiBwcmVkaWN0aW5nIHRoZSBmbGlnaHQgcHJpY2VzIGFzIHRoZSBtb2RlbCBoYXMgdGhlIHNtYWxsZXN0IG1lYW4gYWJzb2x1dGUgZXJyb3IgYW5kIGhpZ2hlc3QgY29ycmVsYXRpb24gY29lZmZpY2llbnQuCgpgYGB7cn0KIyBsaW5lYXIgc3ZtIG1vZGVsCnMgPC0gc3ZtKHByaWNlIH4gZGVwYXJ0dXJlX3RpbWUgKyBkdXJhdGlvbiArIGRheXNfbGVmdCArIHN0b3BzICsgc291cmNlX2NpdHkgKyBhaXJsaW5lICsgY2xhc3MgKyBkZXN0aW5hdGlvbl9jaXR5LCAKICAgICAgICAgc2FtcGxlX2RhdGEsIAogICAgICAgICBrZXJuZWw9ImxpbmVhciIpCnNfcHJlZHMgPC0gcHJlZGljdChzLCB0ZXN0X3NtcCkKbWFlX3MgPC0gbWVhbihhYnMoc19wcmVkcyAtIHRlc3Rfc21wJHByaWNlKSkKbWFlX3MKY3JfcyA8LSBjb3Ioc19wcmVkcyx0ZXN0X3NtcCRwcmljZSkKY3JfcwoKIyByYWRpYWwgc3ZtIG1vZGVsCnIgPC0gc3ZtKHByaWNlIH4gZGVwYXJ0dXJlX3RpbWUgKyBkdXJhdGlvbiArIGRheXNfbGVmdCArIHN0b3BzICsgc291cmNlX2NpdHkgKyBhaXJsaW5lICsgY2xhc3MgKyBkZXN0aW5hdGlvbl9jaXR5LCAKICAgICAgICAgc2FtcGxlX2RhdGEsIAogICAgICAgICBrZXJuZWw9InJhZGlhbCIpCnJfcHJlZHMgPC0gcHJlZGljdChyLCB0ZXN0X3NtcCkKbWFlX3IgPC0gbWVhbihhYnMocl9wcmVkcyAtIHRlc3Rfc21wJHByaWNlKSkKbWFlX3IKY3JfciA8LSBjb3Iocl9wcmVkcyx0ZXN0X3NtcCRwcmljZSkKY3JfcgoKIyBwb2x5IHN2bSBtb2RlbApwb2x5IDwtIHN2bShwcmljZSB+IGRlcGFydHVyZV90aW1lICsgZHVyYXRpb24gKyBkYXlzX2xlZnQgKyBzdG9wcyArIHNvdXJjZV9jaXR5ICsgYWlybGluZSArIGNsYXNzICsgZGVzdGluYXRpb25fY2l0eSwgCiAgICAgICAgICAgIHNhbXBsZV9kYXRhLCAKICAgICAgICAgICAga2VybmVsPSJwb2x5bm9taWFsIikKcG9seV9wcmVkcyA8LSBwcmVkaWN0KHBvbHksIHRlc3Rfc21wKQptYWVfcCA8LSBtZWFuKGFicyhwb2x5X3ByZWRzIC0gdGVzdF9zbXAkcHJpY2UpKQptYWVfcApjcl9wIDwtIGNvcihwb2x5X3ByZWRzLHRlc3Rfc21wJHByaWNlKQpjcl9wCmBgYAoKQWZ0ZXIgdHVuaW5nIHRoZSByYWRpYWwgU1ZNIG1vZGVsLCB0aGUgbW9kZWwgYmVjYW1lIG1vcmUgYWNjdXJhdGUgYXMgdGhlIG1lYW4gYWJzb2x1dGUgZXJyb3IgZGVjcmVhc2VkIGFuZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgaW5jcmVhc2VkLiBUaGUgYmVzdCBwYXJhbWV0ZXJzIGZvciBnYW1tYSBhbmQgY29zdCBhcmUgMC4xIGFuZCAxMCwgcmVzcGVjdGl2ZWx5LiBBIHNtYWxsZXIgcmFuZG9tIHN1YnNldCBvZiA1MDAwIGVudHJpZXMgd2FzIHVzZWQgdG8gdHJhaW4gdGhlIGZpbmUtdHVuZWQgbW9kZWwgZm9yIGVmZmljaWVuY3kuCgpgYGB7cn0KIyBUYWtlIGEgc21hbGxlciBzYW1wbGUKc2FtcGxlX2RhdGEyIDwtIHRyYWluX3NtcFtzYW1wbGUobnJvdyh0cmFpbl9zbXApLCA1MDAwKSwgXQoKIyBGaW5kIHRoZSBiZXN0IHBhcmFtZXRlcnMKcCA8LSB0dW5lLnN2bShwcmljZSB+IGRlcGFydHVyZV90aW1lICsgZHVyYXRpb24gKyBkYXlzX2xlZnQgKyBzdG9wcyArIHNvdXJjZV9jaXR5ICsgYWlybGluZSArIGNsYXNzICsgZGVzdGluYXRpb25fY2l0eSwgCiAgICAgICAgICAgICAgZGF0YSA9IHNhbXBsZV9kYXRhMiwgCiAgICAgICAgICAgICAgZ2FtbWE9YygwLjAxLCAwLjEsIDEpLCAKICAgICAgICAgICAgICBjb3N0PWMoMSwgNSwgMTApICwgCiAgICAgICAgICAgICAga2VybmVsID0gInJhZGlhbCIpIAoKIyBUcmFpbiB0aGUgbW9kZWwgd2l0aCB0aGUgYmVzdCBwYXJhbWV0ZXJzCm5ld19yIDwtIHN2bShwcmljZSB+IGRlcGFydHVyZV90aW1lICsgZHVyYXRpb24gKyBkYXlzX2xlZnQgKyBzdG9wcyArIHNvdXJjZV9jaXR5ICsgYWlybGluZSArIGNsYXNzICsgZGVzdGluYXRpb25fY2l0eSwgCiAgICAgICAgICAgICBzYW1wbGVfZGF0YSwgCiAgICAgICAgICAgICBrZXJuZWw9InJhZGlhbCIsIAogICAgICAgICAgICAgZ2FtbWE9cCRiZXN0LnBhcmFtZXRlcnMkZ2FtbWEsIAogICAgICAgICAgICAgY29zdD1wJGJlc3QucGFyYW1ldGVycyRjb3N0KQpuZXdfcl9wcmVkcyA8LSBwcmVkaWN0KG5ld19yLCB0ZXN0X3NtcCkKCiMgQ2FsY3VsYXRlIE1lYW4gQWJzb2x1dGUgRXJyb3IgKE1BRSkKbmV3X21hZV9yIDwtIG1lYW4oYWJzKG5ld19yX3ByZWRzIC0gdGVzdF9zbXAkcHJpY2UpKQpuZXdfbWFlX3IKCiMgQ2FsY3VsYXRlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50Cm5ld19jcl9yIDwtIGNvcihuZXdfcl9wcmVkcyx0ZXN0X3NtcCRwcmljZSkKbmV3X2NyX3IKYGBgCgojIyBDb25jbHVzaW9uCgpGb3IgdGhpcyBwcm9qZWN0IHdlIHNvdWdodCBvdXQgdG8gc2VlIGlmIHRoZXJlIGFyZSBmYWN0b3JzIGluZmx1ZW5jaW5nIHRoZSBmbGlnaHQgcHJpY2VzLiBGb3Igb3VyIGZpcnN0IHF1ZXN0aW9uLCB3ZSBhc2sgaWYgdGhlcmUgd2FzIGEgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgdGltZSBvZiBkZXBhcnR1cmUgYW5kIHRoZSBwcmljZSBvZiB0aGUgdGlja2V0cy4gRnJvbSBhIG51bWJlciBvZiB2aXN1YWxpemF0aW9ucyB0aGF0IHdlIGRpZCwgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIGlzIGRlZmluaXRlbHkgYSBjb3JyZWxhdGlvbiBhcyBsYXRlIG5pZ2h0IHRpY2tldHMgYXJlIHVzdWFsbHkgdGhlIGNoZWFwZXN0IHdpdGggdmVyeSBsaXR0bGUgdmFyaWFiaWxpdHkgaW4gcHJpY2Ugd2l0aCBhIG1lYW4gcHJpY2Ugb2YgOTI5NS4zIFJ1cGVlcy4gRm9yIHRoZSByZW1haW5pbmcgZGVwYXJ0dXJlIHRpbWVzLCB3ZSBjYW4gc2VlIHRoYXQgdGhlcmUgaXMgbm90IG11Y2ggZGlmZmVyZW5jZSBpbiBwcmljZXMgYXMgdGhlIG1lYW5zIG9mIHRoZSByZXN0IG9mIHRoZSBkZXBhcnR1cmUgdGltZXMgY2VudGVyIGFyb3VuZCAyMTAwMCBSdXBlZXMuCgpGb3Igb3VyIHNlY29uZCBxdWVzdGlvbiwgd2UgdHJpZWQgdG8gc2VlIGlmIHRoZXJlIHdhcyBhIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGR1cmF0aW9uIG9mIHRoZSBmbGlnaHQgYW5kIHRoZSB0aWNrZXQgb2YgdGhlIHByaWNlLiBGcm9tIGp1c3QgbG9va2luZyBhIHRoZSB0cmVuZCBsaW5lIGZyb20gdGhlIHNjYXR0ZXIgcGxvdCwgd2UgY2FuIHNlZSBhIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGR1cmF0aW9uIGFuZCB0aGUgcHJpY2Ugb2YgdGhlIHRpY2tldC4gVXBvbiBmdXJ0aGVyIGluc3BlY3Rpb24gb2YgdGhlIHNjYXR0ZXIgcGxvdCwgYWZ0ZXIgZGlmZmVyZW50aWF0aW5nIHRoZSBjbGFzc2VzIG9mIHRoZSB0aWNrZXRzLCB3ZSBjYW4gc2VlIHRoZSBidXNpbmVzcyBjbGFzcyB0aWNrZXRzIGdldCBldmVuIG1vcmUgZXhwZW5zaXZlIHdpdGggZHVyYXRpb24gdGhhbiBlY29ub215IHRpY2tldHMuCgpGb3Igb3VyIGxhc3QgcXVlc3Rpb24sIHdlIHdhbnRlZCB0byBzZWUgaWYgdGhlcmUgd2FzIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgZGF5cyBsZWZ0IGZyb20gZGVwYXJ0dXJlIGFuZCB0aGUgcHJpY2Ugb2YgdGhlIHRpY2tldC4gV2UgdXNlZCBhIHNjYXR0ZXIgcGxvdCBjYXRlZ29yaXplZCBieSBzb3VyY2UgYW5kIGRlc3RpbmF0aW9uIGNpdHkgYW5kIGZvciBldmVyeSBwbG90IHdlIGNhbiBzZWUgdGhhdCB0aGVyZSBpcyBhIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHByaWNlIGFuZCB0aGUgZGF5cyBsZWZ0IGZyb20gZGVwYXJ0dXJlLCB0aGUgZnVydGhlciB0aGUgZGVwYXJ0dXJlIGRhdGUgaXMgdGhlIGNoZWFwZXIgdGhlIHRpY2tldHMuCgpGb3Igb3VyIGZpcnN0IHRyZWUgbW9kZWwsIHdlIHVzZWQgb25seSAzIGluZGVwYW5kZW50IHZhcmlhYmxlcyAoZGVwYXJ0dXJlIHRpbWUsIGR1cmF0aW9uLCBkYXlzX2xlZnQpIHdpdGggb3VyIHRhcmdldCB2YXJpYWJsZSwgcHJpY2UsIHRvIHRyYWluIG91ciBtb2RlbC4gVGhpcyBkaWQgbm90IGxlYWQgdG8gb3B0aW1hbCByZXN1bHRzIGFzIHdlIGdvdCBhIG1lYW4gYWJzb2x1dGUgZXJyb3Igb2YgMTg4NzkuNCBhbmQgYSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAwLjI1OTIuIFNvIGZvciBvdXIgc2Vjb25kIHRyZWUgbW9kZWwsIHdlIHVzZWQgYWxsIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc2V0IHRvIHRyYWluIHRoZSBtb2RlbCBhbmQgd2UgcmVjZWl2ZWQgYmV0dGVyIHJlc3VsdHMgd2l0aCBhIG1lYW4gYWJzb2x1dGUgZXJyb3Igb2YgNDMxNS4xNzYgYW5kIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgMC45NTcuCgpGb3Igb3VyIGxpbmVhciBtb2RlbCwgd2UgdXNlZCBhbGwgdGhlIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBzZXQgdG8gdHJhaW4gdGhlIG1vZGVsIGFuZCBhIG1lYW4gYWJzb2x1dGUgZXJyb3Igb2YgNDU2MC4yOTggYW5kIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgMC45NTQuCgpGb3Igb3VyIFNWTXMsIGZpcnN0IHdlIHRyYWluZWQgMSBsaW5lYXIgU1ZNLCAxIHJhZGlhbCBTVk0gYW5kIDEgcG9seW5vbWlhbCBTVk0gdXNpbmcgYWxsIHRoZSB2YXJpYWJsZXMgZnJvbSB0aGUgZGF0YXNldC4gVGhlIHRhYmxlIGJlbG93IHNob3dzIHRoZSBtZWFuIGFic29sdXRlIHZhbHVlIGFuZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgZm9yIGVhY2ggb2YgdGhlc2UgbW9kZWxzLgoKYGBgICAgICAgICAgCiAgICAgICAgICAgICAgICBNZWFuIGFic29sdXRlIHZhbHVlICAgICAgICAgQ29ycmVsYXRpb24gY29lZmZpY2llbnQgCkxpbmVhciBTVk0gICAgICAgNDE4My4zNzUgICAgICAgICAgICAgICAgICAgICAgICAgMC45NTE0MjA2ICAgICAgICAgICAgICAgICAgICAgICAgClJhZGlhbCBTVk0gICAgICAgMzEzOS43MjcgICAgICAgICAgICAgICAgICAgICAgICAgMC45NzMxNzM5ICAgICAgICAgICAgICAgICAgICAgICAKUG9seW5vbWlhbCBTVk0gICA3NzM5LjgzMiAgICAgICAgICAgICAgICAgICAgICAgICAwLjkxNTY4ICAgICAgICAgICAKYGBgCgpXZSBkZWNpZGVkIHRvIHR1bmUgdGhlIFJhZGlhbCBTVk0gdG8gbWFrZSBpdCBtb3JlIGFjY3VyYXRlIGJ5IHVzaW5nIHRoZSBiZXN0IGdhbW1hIGFuZCBjb3N0IHZhbHVlcy4gQWZ0ZXIgdHVuaW5nIHRoZSBtb2RlbHMsIHRoZSBNQUUgZGVjcmVhc2VkIHRvIDI4NTEuNzA0IGFuZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgcm9zZSB0byAwLjk3ODMuCgpBZnRlciBldmFsdWF0aW5nIGFsbCBvdXIgbW9kZWxzLCB3ZSBjYW4gc2VlIHRoYXQgUmFkaWFsIFNWTSBoYXMgdGhlIGJlc3QgcGVyZm9ybWFuY2Ugb3ZlcmFsbCBldmVuIGJlZm9yZSB0aGUgdHVuaW5nIHdpdGggYSBNQUUgb2YgMzEzOS43MjcgYW5kIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgMC45NzMuCgpGcm9tIHRoaXMgcHJvamVjdCwgd2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlcmUgYXJlIGRlZmluaXRlbHkgZmFjdG9ycyBzdWNoIGFzIGRlcGFydHVyZSB0aW1lLCBkdXJhdGlvbiBhbmQgdGhlIGRheXMgbGVmdCBmcm9tIGRlcGFydHVyZSBhZmZlY3RpbmcgdGhlIHByaWNlIG9mIGZsaWdodCB0aWNrZXRzLgoKQ2l0YXRpb25zCgpbMV0gamFuLWdseCwg4oCcU2NhdHRlcnBsb3Qgd2l0aCB0b28gbWFueSBwb2ludHMs4oCdIFN0YWNrIE92ZXJmbG93LCBPY3QuIDEwLCAyMDExLiA8aHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNzcxNDY3Ny9zY2F0dGVycGxvdC13aXRoLXRvby1tYW55LXBvaW50cy81ODUyMzk1NiM1ODUyMzk1Nj4KClsyXSDigJxIb3cgdG8gUHJ1bmUgYSBUcmVlIGluIFI/LOKAnSBHZWVrc2ZvckdlZWtzLCBKdW4uIDEzLCAyMDI0LiA8aHR0cHM6Ly93d3cuZ2Vla3Nmb3JnZWVrcy5vcmcvaG93LXRvLXBydW5lLWEtdHJlZS1pbi1yLz4KClszXSA8aHR0cHM6Ly93d3cuaWNhby5pbnQvYW5udWFsLXJlcG9ydC0yMDE5L1BhZ2VzL3RoZS13b3JsZC1vZi1haXItdHJhbnNwb3J0LWluLTIwMTkuYXNweCM+Olx+OnRleHQ9VGhlJTIwNC41JTIwYmlsbGlvbiUyMHNjaGVkdWxlZCUyMHBhc3NlbmdlcnMsc29tZSUyMDkwJTIwbWlsbGlvbiUyMGluJTIwMjA0MC4mdGV4dD1UaGUlMjB3b3JsZCdzJTIwbWFqb3IlMjBtYW51ZmFjdHVyZXJzJTIwZGVsaXZlcmVkLDgyMiUyMG5ldyUyMGFpcmNyYWZ0JTIwbmV0JTIwb3JkZXJzLgo=